package cn.xy.ymcc.service.impl;

import cn.xy.ymcc.domain.Course;
import cn.xy.ymcc.domain.CourseMarket;
import cn.xy.ymcc.domain.CourseOrder;
import cn.xy.ymcc.domain.CourseOrderItem;
import cn.xy.ymcc.dto.CourseOrderCreateParamsDto;
import cn.xy.ymcc.dto.PayDto;
import cn.xy.ymcc.exception.GlobalException;
import cn.xy.ymcc.feign.CourseUserLearnFeignClient;
import cn.xy.ymcc.mapper.CourseOrderMapper;
import cn.xy.ymcc.result.JSONResult;
import cn.xy.ymcc.service.ICourseOrderItemService;
import cn.xy.ymcc.service.ICourseOrderService;
import cn.xy.ymcc.util.AssertUtil;
import cn.xy.ymcc.util.CodeGenerateUtils;
import cn.xy.ymcc.vo.CourseItemVo;
import cn.xy.ymcc.vo.CourserOrderVo;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.rocketmq.client.producer.LocalTransactionState;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.client.producer.TransactionSendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author xy.cao
 * @since 2022-07-29
 */
@Service
@Slf4j
public class CourseOrderServiceImpl extends ServiceImpl<CourseOrderMapper, CourseOrder> implements ICourseOrderService {

    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;

    @Autowired
    private CourseUserLearnFeignClient courseInfoForOrderFeignClient;
    @Autowired
    private ICourseOrderItemService courseOrderItemService;

    @Autowired
    private RocketMQTemplate rocketMQTemplate;  //用以发送事务消息

    @Override
    @Transactional
    public String placeOrder(CourseOrderCreateParamsDto dto) {
        //参数校验
        //校验token是否还有效，
        Long loginId = 1L; //设定一个登录id，
        //获取courseId并转换为string格式
        String courseIdsStr = StringUtils.join(dto.getCourseIds(), ",");
        //拼凑key
        String key = courseIdsStr+":"+loginId;
        //查询token，在redis中
        Object tokenTmp = redisTemplate.opsForValue().get(key);
        //校验token
        AssertUtil.isNotNull(tokenTmp,"请重新下单！");
        AssertUtil.isEquals(dto.getToken(),tokenTmp.toString(),"请重新下单");

        //service-order 通过Feign接口去调用service-course获取课程相关的数据
        JSONResult jsonResult = courseInfoForOrderFeignClient.courseOrderInfo(courseIdsStr);
        //校验成功与否
        AssertUtil.isTrue(jsonResult.isSuccess(),"下单失败！");
        //校验数据
        AssertUtil.isNotNull(jsonResult.getData(),"下单失败！");
        //转订单详情页数据对象
        CourserOrderVo orderVo = JSONObject.parseObject(JSON.toJSONString(jsonResult.getData()),CourserOrderVo.class);
        //获取详情页对象中的课程详情
        List<CourseItemVo> courseInfos = orderVo.getCourseInfos();
        //校验
        AssertUtil.isNotNull(courseInfos,"课程详情有误，下单失败");
        //保存主订单，没有总金额
        Date date = new Date();
        CourseOrder order = new CourseOrder();
        order.setCreateTime(date);
        order.setOrderNo(CodeGenerateUtils.generateOrderSn(loginId));
        order.setStatusOrder(0);
        order.setUserId(loginId);
        order.setVersion(0);
        order.setPayType(dto.getPayType());

        //insert(order);
        //4.2 保存子订单 统计出总金额
        StringBuilder sb = new StringBuilder();
        sb.append("课程【");
        //遍历
        courseInfos.forEach(courseInfoVo->{
            Course course = courseInfoVo.getCourse();
            CourseMarket courseMarket = courseInfoVo.getCourseMarket();
            CourseOrderItem item = new CourseOrderItem();
            //根据总表中的订单id来设置子表订单id
           // item.setOrderId(order.getId());
            item.setAmount(courseMarket.getPrice());
            item.setCount(1);
            order.setTotalCount(order.getTotalCount() + 1);
            order.setTotalAmount(order.getTotalAmount().add(item.getAmount()));
            sb.append(course.getName()).append(",");
            item.setCreateTime(date);
            item.setCourseId(course.getId());
            item.setCourseName(course.getName());
            item.setCoursePic(course.getPic());
            item.setVersion(order.getVersion());
            item.setOrderNo(order.getOrderNo());
           // courseOrderItemService.insert(item);
            //把子订单放到主订单
            order.getItems().add(item);
        });
        sb.append("】订单");
        //修改
        order.setTitle(sb.toString());
        //updateById(order);

        //发布事务消息
        //将保存主订单和子订单的操作，交给MQ事务监听器
        //message: 用来生成t_pay_order 表的数据库--要支付的数据
        //arg: 用来传递主订单和子订单信息  交给监听器去保存本地事务
        //创建支付对象，数据获取到的值
        PayDto payDto = new PayDto(
                order.getTotalAmount(),
                order.getPayType(),
                null,
                order.getOrderNo(),
                order.getUserId(),
                "额外参数",
                order.getTitle()
        );
        log.info("发送事务消息");

        //消息体
        Message<String> message = MessageBuilder.withPayload(JSON.toJSONString(payDto)).build();
        TransactionSendResult transactionSendResult = rocketMQTemplate.sendMessageInTransaction(
                "service-order-producer",
                "course-order-topic:course-order-tag",
                message,
                order
        );
        log.info("检查事务消息状态");
        LocalTransactionState localTransactionState = transactionSendResult.getLocalTransactionState();
        SendStatus sendStatus = transactionSendResult.getSendStatus();
        if(localTransactionState != LocalTransactionState.COMMIT_MESSAGE || sendStatus != SendStatus.SEND_OK ){
            log.info("校验发送事务消息状态异常");
            throw new GlobalException("下单失败！！");
        }

        //5.删除防重复token
        redisTemplate.delete(key);
        return order.getOrderNo();  //返回订单号
    }


    @Override
    public void saveOrderAndItems(CourseOrder courseOrder) {
        //建议，查询一下是否已经下过单了
        CourseOrder orderTmp = selectOrderByOrderNo(courseOrder.getOrderNo());
        AssertUtil.isNull(orderTmp,"订单已经存在，下单失败");
        //保存订单
        insert(courseOrder);//保存主订单
        courseOrder.getItems().forEach(item->{
            item.setOrderId(courseOrder.getId());
            courseOrderItemService.insert(item);//保存子订单
        });
    }

    /**
     * 根据订单号查询订单
     * @param orderNo
     * @return
     */
    @Override
    public CourseOrder selectOrderByOrderNo(String orderNo) {
        Wrapper<CourseOrder> wrapper = new EntityWrapper<>();
        wrapper.eq("order_no",orderNo);
        return selectOne(wrapper);
    }
}


